package de.wojenko.sps;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;

import com.itextpdf.text.BaseColor;
import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Element;
import com.itextpdf.text.Font;
import com.itextpdf.text.Font.FontFamily;
import com.itextpdf.text.PageSize;
import com.itextpdf.text.Phrase;
import com.itextpdf.text.Rectangle;
import com.itextpdf.text.pdf.PdfContentByte;
import com.itextpdf.text.pdf.PdfPCell;
import com.itextpdf.text.pdf.PdfPTable;
import com.itextpdf.text.pdf.PdfWriter;


public class LandscapeDinA5PDFCardDocument implements java.lang.AutoCloseable {

	private static final Rectangle PAGE_SIZE = PageSize.A5.rotate();
	private static final float PAGE_PADDING = 10;
	private static final float PAGE_WIDTH = PAGE_SIZE.getWidth();
	private static final float PAGE_HEIGHT = PAGE_SIZE.getHeight();
	
	private static final Font HEADER_FONT = new Font(FontFamily.COURIER, 16, Font.NORMAL);
	private static final Font TEXT_FONT = new Font(FontFamily.COURIER, 13, Font.NORMAL);
	private static final Font COMMENT_FONT = new Font(FontFamily.COURIER, 11, Font.ITALIC);
	
	/**
	 * Positions of left top corners of cards on a page.
	 * <pre>
	 *  _______________
	 * |       |       | 
	 * |   1   |   2   | 
	 * |_______|_______| 
	 * |       |       |
	 * |   3   |   4   |
	 * |_______|_______|
	 * </pre>
	 */
	private static final float[][] CARD_POSITIONS  = {
		{
			PAGE_PADDING, PAGE_HEIGHT - PAGE_PADDING
		},
		{
			PAGE_WIDTH/2, PAGE_HEIGHT - PAGE_PADDING
		},
		{
			PAGE_PADDING, (PAGE_HEIGHT/2)
		},
		{
			PAGE_WIDTH/2, (PAGE_HEIGHT/2)
		}
	};

	private static final float CARD_PADDING = 5;
	private static final float CARD_WIDTH = (PAGE_WIDTH / 2) - PAGE_PADDING;
	private static final float CARD_HEIGHT = (PAGE_HEIGHT / 2) - PAGE_PADDING;
	private static final float CARD_HEADER_HEIGHT = 30;

	/**
	 * Definition of four cards
	 * 
	 * float llx, float lly, float urx, float ury
	 **/
	public static final float[][] COLUMNS = {
			// top left card
			{ PAGE_PADDING, // llx
					(PAGE_HEIGHT / 2), // lly
					(PAGE_WIDTH / 2), // urx
					PAGE_HEIGHT - PAGE_PADDING // ury
			},
			// top right card
			{ (PAGE_WIDTH / 2), // llx
					(PAGE_HEIGHT / 2), // lly
					PAGE_WIDTH - PAGE_PADDING, // urx
					PAGE_HEIGHT - PAGE_PADDING // ury
			},
			// bottom left card
			{ PAGE_PADDING, // llx
					PAGE_PADDING, // lly
					(PAGE_WIDTH / 2), // urx
					(PAGE_HEIGHT / 2) // ury
			},
			// bottom right
			{ (PAGE_WIDTH / 2), // llx
					PAGE_PADDING, // lly
					PAGE_WIDTH - PAGE_PADDING, // urx
					(PAGE_HEIGHT / 2) // ury
			} };

	private Document document;
	private PdfWriter writer;
	private final File f;
	private final CardType cardType;
	
	private int cardsOnCurrentPage = 0;
	
	public LandscapeDinA5PDFCardDocument(File f, CardType cardType) {
		this.f = f;
		this.cardType = cardType;
	}
	
	public synchronized Document getDocument() {
		if(document == null) {
			document = new Document(PAGE_SIZE);
		}
		return document;
	}
	
	public synchronized PdfWriter getWriter() throws FileNotFoundException, DocumentException {
		if(writer == null) {
			writer = PdfWriter.getInstance(getDocument(),
					new FileOutputStream(f));
			document.open();
		}
		return writer;
	}
	
	public void addCard(PDFCard pdfCard) throws FileNotFoundException, DocumentException {
		PdfWriter writer = getWriter();
		if(cardsOnCurrentPage > 3) {
			getDocument().newPage();
			cardsOnCurrentPage = 0;
		}
		PdfContentByte directContent = writer.getDirectContent();
		addCard(directContent, pdfCard);
		cardsOnCurrentPage++;
	}
	

	private void addCard(PdfContentByte cb, PDFCard pdfCard) throws DocumentException {
		
		// Create Background
		drawHeaderBackground(cb);
		// Add cut marks
		drawCutMarks(cb);
		// Add Content

		cb.saveState();

		// Card content as table
		PdfPTable tbl = new PdfPTable(2);
		tbl.setTotalWidth(CARD_WIDTH - 2 * CARD_PADDING);
		float[] widths = {49f, 9.0f};
		tbl.setWidths(widths);

		// Content Header
		PdfPCell cell = new PdfPCell(new Phrase(pdfCard.header, HEADER_FONT));
		cell.setHorizontalAlignment(Element.ALIGN_LEFT);
		cell.disableBorderSide(Rectangle.BOX);
		cell.setMinimumHeight(CARD_HEADER_HEIGHT);
		tbl.addCell(cell);

		// Card Type Header
		cell = new PdfPCell(new Phrase(cardType.name, HEADER_FONT));
		cell.setHorizontalAlignment(Element.ALIGN_RIGHT);
		cell.disableBorderSide(Rectangle.BOX);
		tbl.addCell(cell);

		// Add Text
		cell = new PdfPCell(new Phrase(pdfCard.text, TEXT_FONT));
		cell.setHorizontalAlignment(Element.ALIGN_LEFT);
		cell.disableBorderSide(Rectangle.BOX);
		cell.setMinimumHeight(CARD_HEIGHT - (2 * CARD_HEADER_HEIGHT));
		cell.setColspan(2);
		tbl.addCell(cell);
		
		// Add Comment
		cell = new PdfPCell(new Phrase(pdfCard.comment, COMMENT_FONT));
		cell.setHorizontalAlignment(Element.ALIGN_LEFT);
		cell.disableBorderSide(Rectangle.BOX);
		cell.setMinimumHeight(CARD_HEADER_HEIGHT);
		cell.setColspan(2);
		tbl.addCell(cell);

		tbl.writeSelectedRows(0, -1, CARD_POSITIONS[cardsOnCurrentPage][0]+CARD_PADDING, CARD_POSITIONS[cardsOnCurrentPage][1], cb);
		cb.restoreState();

		// Add Comment
	}

	private void drawHeaderBackground(PdfContentByte cb) {
		cb.saveState();
		cb.setColorFill(cardType.color);
		cb.rectangle(CARD_POSITIONS[cardsOnCurrentPage][0], CARD_POSITIONS[cardsOnCurrentPage][1]-CARD_HEADER_HEIGHT, CARD_WIDTH, CARD_HEADER_HEIGHT);
		cb.fill();
		cb.restoreState();

		cb.saveState();
		cb.setColorStroke(BaseColor.BLACK);
		cb.setLineWidth(2.0f); // Make a bit thicker than 1.0 default
		
		float y = CARD_POSITIONS[cardsOnCurrentPage][1] - CARD_HEADER_HEIGHT + CARD_PADDING;
		cb.moveTo(CARD_POSITIONS[cardsOnCurrentPage][0] + CARD_PADDING, y);
		cb.lineTo(CARD_POSITIONS[cardsOnCurrentPage][0] + CARD_WIDTH - CARD_PADDING, y);
		cb.stroke();
		cb.restoreState();
	}

	private void drawCutMarks(PdfContentByte cb) {
		// top left
		drawCutMark(cb, CARD_POSITIONS[cardsOnCurrentPage][0], CARD_POSITIONS[cardsOnCurrentPage][1]);
		// top right
		drawCutMark(cb, CARD_POSITIONS[cardsOnCurrentPage][0]+CARD_WIDTH, CARD_POSITIONS[cardsOnCurrentPage][1]);
		// lower left
		drawCutMark(cb, CARD_POSITIONS[cardsOnCurrentPage][0], CARD_POSITIONS[cardsOnCurrentPage][1]-CARD_HEIGHT);
		// lower  right
		drawCutMark(cb, CARD_POSITIONS[cardsOnCurrentPage][0]+CARD_WIDTH, CARD_POSITIONS[cardsOnCurrentPage][1]-CARD_HEIGHT);
	}

	private void drawCutMark(PdfContentByte cb, float x, float y) {

		// horizontal stroke (y stays)
		cb.setColorStroke(BaseColor.BLACK);
		cb.setLineWidth(0.1f); // Make a bit thicker than 1.0 default
		
		cb.moveTo(x - (PAGE_PADDING / 2), y);
		cb.lineTo(x + (PAGE_PADDING / 2), y);
		cb.stroke();

		// vertical stroke (x stays)
		cb.moveTo(x, y - (PAGE_PADDING / 2));
		cb.lineTo(x, y + (PAGE_PADDING / 2));
		cb.stroke();
	}

	@Override
	public synchronized void close() {
		if(document != null && document.isOpen()) {
			document.close();
		}
	}
}
